﻿// <copyright file="NetworkTraverse.cs" company="City of Portland, BES-ASM">
// </copyright>
// <summary>NetworkTraverse implementation</summary>

namespace BESASM.EMGAATS.BusinessClasses
{
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;

  /// <summary>
  /// Network Traverse Class
  /// </summary>
  public class NetworkTraverse
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="NetworkTraverse" /> class.
    /// </summary>
    public NetworkTraverse()
    {
     this.SubNetworkLinkIDs = new List<int>();
    }

    // do I need private set or just get

    /// <summary>
    /// Gets List of sub-network linkIds
    /// </summary>
    public List<int> SubNetworkLinkIDs { get; private set; }

    /// <summary>
    /// Traverses a Network and returns a list of links
    /// </summary>
    /// <param name="parentNetwork">A Network with no validity checks required</param>
    /// <param name="roots">One or more link IDs to start traversal</param>
    /// <param name="stops">Zero or more link IDs to terminate traversal</param>
    /// <returns>List of link IDs</returns>
    public List<int> SelectSubnetworkLinkIDs(Network parentNetwork, List<int> roots, List<int> stops)
    {
      int subnetcount;
      this.SubNetworkLinkIDs.Clear();

      List<int> validroots = roots.Where(root => parentNetwork.Links.Contains(root)).ToList();
      List<int> validstops = stops.Where(stop => parentNetwork.Links.Contains(stop)).ToList();

      parentNetwork.Optimize();
      subnetcount = this.Traverse(parentNetwork, validroots, validstops);
      return this.SubNetworkLinkIDs;
    }

    // every visited edge gets added to the list
    private int Traverse(Network parentNetwork, List<int> rootedgeIDs, List<int> stops)
    {
      int edgeCount = 0;
      foreach (int edge in rootedgeIDs)
      {
        // if the root is valid or if it has already been visited then don't go there 
        if (this.SubNetworkLinkIDs.Contains(edge))
        {
          continue;
        }

        // we have not been here so mark it as visited
        ++edgeCount;
        this.SubNetworkLinkIDs.Add(edge);

        // stop if the root is a stop link
        if (stops != null && stops.Contains(edge))
        {
          continue;
        }

        // get the node once to avoid muliple calls to get ids
        INode thisUSnode = parentNetwork.Links[edge].USNode;

        // if this edge has a null US node we stop 
        if (thisUSnode == null)
        {
          continue;
        }
        
        // build a list of roots for the recursive call
        List<int> newrootedgeIDs = thisUSnode.UpstreamLinks.ConvertAll(link => link.Id);

        /* this section to be deleted
        // avoid multiple executions of LINQ query by intrating through all of the links and building the list as we go
        foreach (ILink link in parentNetwork.Links)
        {
          if (link.DSNode != null)
          {
            if (link.DSNode == thisUSnode)
            {
              newrootedgeIDs.Add(link.Id);
            }
          }
        }
         */
        
        // finally the recursive call
        edgeCount += this.Traverse(parentNetwork, newrootedgeIDs, stops);
      }

      return edgeCount;
    }
  }
}
